From: Keir Fraser Date: Thu, 20 Sep 2007 13:15:45 +0000 (+0100) Subject: cpufreq: Support cpufreq updates on AMD hardware by dom0 kernel. X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~14937^2~54 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https:/%22bookmarks://%22/%22http:/www.example.com/cgi/%22https:/%22bookmarks:/%22?a=commitdiff_plain;h=407d514591ab44061b05e1f7a20efde369d2b2b4;p=xen.git cpufreq: Support cpufreq updates on AMD hardware by dom0 kernel. Signed-off-by: Mark Langsdorf Signed-off-by: Keir Fraser --- diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 86903a8e65..2080e70961 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -1378,10 +1378,9 @@ static void continue_hypercall_on_cpu_helper(struct vcpu *v) regs->eax = info->func(info->data); v->arch.schedule_tail = info->saved_schedule_tail; - v->cpu_affinity = info->saved_affinity; + v->arch.continue_info = NULL; xfree(info); - v->arch.continue_info = NULL; vcpu_set_affinity(v, &v->cpu_affinity); schedule_tail(v); @@ -1392,6 +1391,7 @@ int continue_hypercall_on_cpu(int cpu, long (*func)(void *data), void *data) struct vcpu *v = current; struct migrate_info *info; cpumask_t mask = cpumask_of_cpu(cpu); + int rc; if ( cpu == smp_processor_id() ) return func(data); @@ -1403,12 +1403,19 @@ int continue_hypercall_on_cpu(int cpu, long (*func)(void *data), void *data) info->func = func; info->data = data; info->saved_schedule_tail = v->arch.schedule_tail; - v->arch.schedule_tail = continue_hypercall_on_cpu_helper; - info->saved_affinity = v->cpu_affinity; + + v->arch.schedule_tail = continue_hypercall_on_cpu_helper; v->arch.continue_info = info; - vcpu_set_affinity(v, &mask); + rc = vcpu_set_affinity(v, &mask); + if ( rc ) + { + v->arch.schedule_tail = info->saved_schedule_tail; + v->arch.continue_info = NULL; + xfree(info); + return rc; + } /* Dummy return value will be overwritten by new schedule_tail. */ BUG_ON(!test_bit(SCHEDULE_SOFTIRQ, &softirq_pending(smp_processor_id()))); diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c index 24568db224..86180d1a73 100644 --- a/xen/arch/x86/platform_hypercall.c +++ b/xen/arch/x86/platform_hypercall.c @@ -40,6 +40,11 @@ DEFINE_SPINLOCK(xenpf_lock); extern spinlock_t xenpf_lock; #endif +static long cpu_frequency_change_helper(void *data) +{ + return cpu_frequency_change(*(uint64_t *)data); +} + ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op) { ret_t ret = 0; @@ -280,6 +285,15 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op) ret = acpi_enter_sleep(&op->u.enter_acpi_sleep); break; + case XENPF_change_freq: + ret = -EINVAL; + if ( op->u.change_freq.flags != 0 ) + break; + ret = continue_hypercall_on_cpu(op->u.change_freq.cpu, + cpu_frequency_change_helper, + &op->u.change_freq.freq); + break; + default: ret = -ENOSYS; break; diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c index 5465cc056e..7b23426c6e 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -722,6 +722,27 @@ void update_domain_wallclock_time(struct domain *d) spin_unlock(&wc_lock); } +int cpu_frequency_change(u64 freq) +{ + struct cpu_time *t = &this_cpu(cpu_time); + u64 curr_tsc; + + local_irq_disable(); + set_time_scale(&t->tsc_scale, freq); + rdtscll(curr_tsc); + t->local_tsc_stamp = curr_tsc; + t->stime_local_stamp = get_s_time(); + t->stime_master_stamp = read_platform_stime(); + local_irq_enable(); + + /* A full epoch should pass before we check for deviation. */ + set_timer(&t->calibration_timer, NOW() + EPOCH); + if ( smp_processor_id() == 0 ) + platform_time_calibration(); + + return 0; +} + /* Set clock to after 00:00:00 UTC, 1 January, 1970. */ void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base) { @@ -866,12 +887,14 @@ static void local_time_calibration(void *unused) error_factor, calibration_mul_frac, tsc_shift); #endif - /* Record new timestamp information. */ + /* Record new timestamp information, atomically w.r.t. interrupts. */ + local_irq_disable(); t->tsc_scale.mul_frac = calibration_mul_frac; t->tsc_scale.shift = tsc_shift; t->local_tsc_stamp = curr_tsc; t->stime_local_stamp = curr_local_stime; t->stime_master_stamp = curr_master_stime; + local_irq_enable(); update_vcpu_system_time(current); diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index fea688bf11..16cb989b85 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -1728,10 +1728,16 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) v->arch.guest_context.gs_base_user = res; break; #endif + case MSR_K8_FIDVID_STATUS: + case MSR_K8_FIDVID_CTL: + if ( (cpufreq_controller != FREQCTL_dom0_kernel) || + (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) || + wrmsr_safe(regs->ecx, eax, edx) ) + goto fail; + break; default: if ( wrmsr_hypervisor_regs(regs->ecx, eax, edx) ) break; - if ( (rdmsr_safe(regs->ecx, l, h) != 0) || (eax != l) || (edx != h) ) gdprintk(XENLOG_WARNING, "Domain attempted WRMSR %p from " @@ -1764,6 +1770,13 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) regs->edx = v->arch.guest_context.gs_base_user >> 32; break; #endif + case MSR_K8_FIDVID_CTL: + case MSR_K8_FIDVID_STATUS: + if ( (cpufreq_controller != FREQCTL_dom0_kernel) || + (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) || + rdmsr_safe(regs->ecx, regs->eax, regs->edx) ) + goto fail; + break; case MSR_EFER: if ( rdmsr_safe(regs->ecx, regs->eax, regs->edx) ) goto fail; diff --git a/xen/common/schedule.c b/xen/common/schedule.c index 50aacafb61..9c040477dc 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -42,6 +42,17 @@ string_param("sched", opt_sched); static unsigned int opt_dom0_vcpus_pin; boolean_param("dom0_vcpus_pin", opt_dom0_vcpus_pin); +enum cpufreq_controller cpufreq_controller; +static void __init setup_cpufreq_option(char *str) +{ + if ( !strcmp(str, "dom0-kernel") ) + { + cpufreq_controller = FREQCTL_dom0_kernel; + opt_dom0_vcpus_pin = 1; + } +} +custom_param("cpufreq", setup_cpufreq_option); + #define TIME_SLOP (s32)MICROSECS(50) /* allow time to slip a bit */ /* Various timer handlers. */ diff --git a/xen/include/asm-x86/msr.h b/xen/include/asm-x86/msr.h index 1e24537566..069b29e689 100644 --- a/xen/include/asm-x86/msr.h +++ b/xen/include/asm-x86/msr.h @@ -360,6 +360,9 @@ static inline void write_efer(__u64 val) #define MSR_K8_VM_CR 0xC0010114 #define MSR_K8_VM_HSAVE_PA 0xC0010117 +#define MSR_K8_FIDVID_CTL 0xC0010041 +#define MSR_K8_FIDVID_STATUS 0xC0010042 + /* MSR_K8_VM_CR bits: */ #define _K8_VMCR_SVME_DISABLE 4 #define K8_VMCR_SVME_DISABLE (1 << _K8_VMCR_SVME_DISABLE) diff --git a/xen/include/asm-x86/time.h b/xen/include/asm-x86/time.h index 773c312770..23cbbf2b79 100644 --- a/xen/include/asm-x86/time.h +++ b/xen/include/asm-x86/time.h @@ -29,4 +29,6 @@ void init_percpu_time(void); struct ioreq; int dom0_pit_access(struct ioreq *ioreq); +int cpu_frequency_change(u64 freq); + #endif /* __X86_TIME_H__ */ diff --git a/xen/include/public/platform.h b/xen/include/public/platform.h index d1a44835de..ad7847a9d9 100644 --- a/xen/include/public/platform.h +++ b/xen/include/public/platform.h @@ -164,6 +164,16 @@ struct xenpf_enter_acpi_sleep { typedef struct xenpf_enter_acpi_sleep xenpf_enter_acpi_sleep_t; DEFINE_XEN_GUEST_HANDLE(xenpf_enter_acpi_sleep_t); +#define XENPF_change_freq 52 +struct xenpf_change_freq { + /* IN variables */ + uint32_t flags; /* Must be zero. */ + uint32_t cpu; /* Physical cpu. */ + uint64_t freq; /* New frequency (Hz). */ +}; +typedef struct xenpf_change_freq xenpf_change_freq_t; +DEFINE_XEN_GUEST_HANDLE(xenpf_change_freq_t); + struct xen_platform_op { uint32_t cmd; uint32_t interface_version; /* XENPF_INTERFACE_VERSION */ @@ -176,6 +186,7 @@ struct xen_platform_op { struct xenpf_platform_quirk platform_quirk; struct xenpf_firmware_info firmware_info; struct xenpf_enter_acpi_sleep enter_acpi_sleep; + struct xenpf_change_freq change_freq; uint8_t pad[128]; } u; }; diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index f863f4a837..cf5342ccf1 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -499,6 +499,10 @@ static inline void vcpu_unblock(struct vcpu *v) #define is_hvm_domain(d) ((d)->is_hvm) #define is_hvm_vcpu(v) (is_hvm_domain(v->domain)) +extern enum cpufreq_controller { + FREQCTL_none, FREQCTL_dom0_kernel +} cpufreq_controller; + #endif /* __SCHED_H__ */ /* diff --git a/xen/include/xen/time.h b/xen/include/xen/time.h index 0c7c80ebde..e70ad5350e 100644 --- a/xen/include/xen/time.h +++ b/xen/include/xen/time.h @@ -1,28 +1,10 @@ -/**************************************************************************** - * (C) 2002 - Rolf Neugebauer - Intel Research Cambridge - **************************************************************************** - * - * File: time.h - * Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk) - * Changes: - * - * Date: Nov 2002 +/****************************************************************************** + * time.h * - * Environment: Xen Hypervisor - * Description: This file provides a one stop shop for all time related - * issues within the hypervisor. - * - * The Hypervisor provides the following notions of time: - * Cycle Counter Time, System Time, Wall Clock Time, and - * Domain Virtual Time. - * - **************************************************************************** - * $Id: h-insert.h,v 1.4 2002/11/08 16:03:55 rn Exp $ - **************************************************************************** + * Copyright (c) 2002-2003 Rolf Neugebauer + * Copyright (c) 2002-2005 K A Fraser */ - - #ifndef __XEN_TIME_H__ #define __XEN_TIME_H__